package com.caocaog.market.service.impl;

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.caocaog.market.constant.MarketConstant;
import com.caocaog.market.data.transfer.service.MkSiteBasicService;
import com.caocaog.market.entity.Member;
import com.caocaog.market.entity.TiktokEncryptedParam;
import com.caocaog.market.service.TiktokService;
import com.caocaog.market.service.MemberService;
import com.caocaog.market.util.BytedanceMicroApp;
import com.caocaog.market.util.DecryptUtil;
import com.caocaog.market.vo.MemberLoginSuccessVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.exception.CheckFailedException;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.util.PasswordUtil;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author liguang
 * @version 1.0.0
 * @Project jeecg-boot
 * @Package com.caocaog.market.service.impl
 * @ClassName TiktokServiceImpl.java
 * @createTime 2022年04月28日 19:13:00
 * @Description 抖音对接service接口实现
 */
@Service
@Slf4j
public class TiktokServiceImpl implements TiktokService {
    @Value("${tiktok.app-id}")
    private String appid;
    @Value("${tiktok.secret}")
    private String secret;
    @Value("${tiktok.access-token-url}")
    private String accessTokenUrl;
    @Value("${tiktok.client-credential}")
    private String clientCredential;
    @Value("${tiktok.code-2-session-url}")
    private String codeToSessionUrl;
    @Autowired
    private RedisUtil redisUtil;
    private final String cacheFolder = "tiktok:info";

    @Autowired(required = false)
    private MemberService memberService;
    @Autowired(required = false)
    private MkSiteBasicService mkSiteBasicService;

    /**
     * 获取access_token
     */
    @Override
    public Result getAccessToken() {
        Map<String, Object> params = new HashMap<>();
        params.put("appid", appid);
        params.put("secret", secret);
        params.put("grant_type", clientCredential);
        String relt = HttpUtil.post(accessTokenUrl, JSONUtil.toJsonStr(params));
        log.info("获取抖音access_token返回的数据：" + relt);
        //正常返回的数据格式如下：
        //        {
        //            "err_no": 0,
        //                "err_tips": "success",
        //                "data": {
        //            "access_token": "0801121***********",
        //                    "expires_in": 7200
        //        }
        //        }
        // 错误返回示例
        //        {
        //            "err_no": 40017,
        //                "err_tips": "bad secret",
        //                "data": {
        //            "access_token": "",
        //                    "expires_in": 0
        //        }
        //        }
        JSONObject jObj = JSONUtil.parseObj(relt);
        Object errNo = jObj.get("err_no"), errTips = jObj.get("err_tips");
        if (oConvertUtils.isNotEmpty(errNo) && oConvertUtils.getInt(errNo) == 0 && oConvertUtils.isNotEmpty(errTips) && errTips.equals("success")) {
            // 成功
            JSONObject dataObj = jObj.getJSONObject("data");
            log.info("获取抖音access_token时解析出来的data数据：" + JSONUtil.toJsonStr(dataObj));
            Object tokenObj = dataObj.get("access_token");
            if (oConvertUtils.isNotEmpty(dataObj)) {
                return Result.OK(dataObj);
            }
            return Result.error("获取失败");
        } else {
            // 有错误  或  失败
            log.info("获取抖音access_token失败，错误信息：" + errTips);
            return Result.error("获取失败");
        }
    }

    /**
     * 解密敏感数据获取抖音或头条的用户信息
     *
     * @param param
     * @return
     */
    @Override
    public Result decryptUserInfo(TiktokEncryptedParam param) {
        log.info(param.toString());
        if (oConvertUtils.isEmpty(param.getCode())) {
            //throw new BusinessException(ToastConstant.ERR_JSCODE);
            return Result.error("参数错误,必要的参数不能为空!");
        }
        // code2Session
        Object object = redisUtil.get(cacheFolder + ":" + param.getCode());
        JSONObject jObj = JSONUtil.parseObj(object);
        if (oConvertUtils.isEmpty(jObj) || !jObj.get("error").equals(0)) {
            return Result.error("获取用户信息失败!");
        }

        log.info("开始进行数据解密------- param = [{}]", JSONUtil.toJsonStr(param));
        String jsonString = DecryptUtil.decrypt(param.getEncryptedData(), jObj.getStr("sessionKey"), param.getIv());
        log.info("解密后的数据为-------  jsonString = [{}]", jsonString);

        return Result.OK(jsonString);
    }

    /**
     * 通过login接口获取到登录凭证后，开发者可以通过服务器发送请求的方式获取 session_key 和 openId。
     *
     * @param code
     * @return
     */
    @Override
    public Result code2Session(String code) {
        // 构造参数
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("appid", appid);
        paramMap.put("secret", secret);
        paramMap.put("code", code);
        // 发送请求
        Map<String, Object> params = new HashMap<>();
        params.put("appid", appid);
        params.put("secret", secret);
        params.put("code", code);
        String relt = HttpUtil.post(codeToSessionUrl, JSONUtil.toJsonStr(params));
        System.out.println(relt);
        if (oConvertUtils.isEmpty(relt)) {
            log.error("获取sessionKey失败, jsonResult 返回为空");
            return Result.error("无法获取必要的信息!");
        }
        // 解析结果
        JSONObject jsonObject = JSONUtil.parseObj(relt);
        int error = jsonObject.getInt("err_no");
        if (error == 0) {
            BytedanceMicroApp.BytedanceMicroAppResult data = jsonObject.getBean("data", BytedanceMicroApp.BytedanceMicroAppResult.class);
            JSONObject jobj = new JSONObject();
            jobj.accumulate("error", error);
            jobj.accumulate("openid", data.getOpenid());
            jobj.accumulate("sessionKey", data.getSession_key());
            jobj.accumulate("anonymousOpenid", data.getAnonymous_openid());
            jobj.accumulate("unionid", data.getUnionid());
            log.info(code);
            // 将获取到的抖音相关信息存入redis
            redisUtil.set(cacheFolder + ":" + code, jobj, JwtUtil.APP_EXPIRE_TIME);
            System.out.println(jobj);
            return Result.OK(jobj);
        } else {
            log.error("获取sessionKey失败, errCode = [{}], errMsg = [{}]");
            //throw new BusinessException(ToastConstant.ERROR_GET_SESSION_KEY);
            return Result.error("获取主要信息失败!");
        }
    }

    @Value("${member.username.prefix}")
    private String memberUsernamePrefix;

    @Override
    public MemberLoginSuccessVO login(Member member) {
        //验证微信用户
        //get openid
        if (StringUtils.isBlank(member.getWxOpenid())) {
            throw new CheckFailedException("缺少openId");
        }
        Member memberOld = this.memberService.getOne(new QueryWrapper<Member>().eq("wx_openid", member.getWxOpenid()).last(" limit 1 "));
        if (null != memberOld) {

            boolean flag = false;
//               Object uniodnid =  redisUtil.get(member.getWxOpenid());
            if (oConvertUtils.isNotEmpty(member.getMobile())) {
                memberOld.setMobile(member.getMobile());
                flag = true;
            }

            if (oConvertUtils.isNotEmpty(member.getNickName())) {
                memberOld.setNickName(member.getNickName());
                flag = true;
            }

            if (oConvertUtils.isNotEmpty(member.getAvatar())) {
                memberOld.setAvatar(member.getAvatar());
                flag = true;
            }
            if (flag) {
                this.memberService.updateById(memberOld);
            }

            String appSign = JwtUtil.appSign(memberOld.getId());
            return new MemberLoginSuccessVO(appSign, memberOld);
        } else {
            String userId = IdWorker.getIdStr(member);
            if (oConvertUtils.isNotEmpty(member.getMobile())) {
                //check
                Member checkMobile = this.memberService.getOne(new QueryWrapper<Member>()
                        .eq("mobile", member.getMobile())
                        .eq("status", 0)
                        .last(" limit 1 "));
                if (oConvertUtils.isEmpty(checkMobile)) {
                    member.setLoginName(member.getMobile());//默认手机号
                } else {
                    //存在手机号
                    throw new CheckFailedException("手机号已存在~");
                }
            } else {
                member.setLoginName(userId);//默认userId
                member.setMobile(userId.substring(11));
            }
            log.info(userId);
            log.info(member.getMobile());

            //新增
            member.setSource(MarketConstant.SOURCE_TK_MINI);
            String defaultUserName = memberUsernamePrefix + "SDX" + userId;
            member.setId(String.valueOf(IdWorker.getId()));
            member.setUserName(defaultUserName);
            member.setCreateTime(new Date());
            member.setCreateBy(defaultUserName);
            member.setDelFlag(CommonConstant.DEL_FLAG_0);
            // 处理密码
            String salt = oConvertUtils.randomGen(8);
            member.setSalt(salt);
            String b;
            if (StringUtils.isBlank(member.getMobile())) {
                b = "0000";
            } else {
                b = member.getMobile().substring(4);
            }
            member.setUserPwd(PasswordUtil.encrypt(member.getUserName(), b, salt));
            member.setLockVersion(1);
            member.setStatus(0);
            //设置分站
            String siteId = this.mkSiteBasicService.getSurroundingSiteId(member.getRegistLat(), member.getRegistLng()).getSiteId();
            log.info("-----设置分站id:" + siteId);
            member.setSiteId(siteId);
            this.memberService.save(member);
            String appSign = JwtUtil.appSign(member.getId());
            return new MemberLoginSuccessVO(appSign, member);
        }

    }

}
